package com.jh.fcsm.util.io;

import com.jh.fcsm.beans.sys.SysFileInfo;
import com.jh.fcsm.common.exception.ServiceException;
import com.jh.fcsm.constant.Constant;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class FileUtil {
    public static final Logger logger = LoggerFactory.getLogger(FileUtil.class);

    private final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();

    private FileUtil(){}

    static {
        getAllFileType(); //初始化文件类型信息
    }
    /**
     * Created on 2010-7-1
     * <p>Discription:[getAllFileType,常见文件头信息]</p>
     * @author:[shixing_11@sina.com]
     */
    private static void getAllFileType() {
        FILE_TYPE_MAP.put("jpg", "FFD8FF"); //JPEG (jpg)
        FILE_TYPE_MAP.put("png", "89504E47"); //PNG (png)
        FILE_TYPE_MAP.put("gif", "47494638"); //GIF (gif)
        FILE_TYPE_MAP.put("tif", "49492A00"); //TIFF (tif)
        FILE_TYPE_MAP.put("bmp", "424D"); //Windows Bitmap (bmp)
        FILE_TYPE_MAP.put("dwg", "41433130"); //CAD (dwg)
        FILE_TYPE_MAP.put("html", "68746D6C3E"); //HTML (html)
        FILE_TYPE_MAP.put("rtf", "7B5C727466"); //Rich Text Format (rtf)
        FILE_TYPE_MAP.put("xml", "3C3F786D6C");
        FILE_TYPE_MAP.put("zip", "504B0304");
        FILE_TYPE_MAP.put("rar", "52617221");
        FILE_TYPE_MAP.put("psd", "38425053"); //Photoshop (psd)
        FILE_TYPE_MAP.put("eml", "44656C69766572792D646174653A"); //Email [thorough only] (eml)
        FILE_TYPE_MAP.put("dbx", "CFAD12FEC5FD746F"); //Outlook Express (dbx)
        FILE_TYPE_MAP.put("pst", "2142444E"); //Outlook (pst)
        FILE_TYPE_MAP.put("xls", "D0CF11E0"); //MS Word
        FILE_TYPE_MAP.put("doc", "D0CF11E0"); //MS Excel 注意：word 和 excel的文件头一样
        FILE_TYPE_MAP.put("mdb", "5374616E64617264204A"); //MS Access (mdb)
        FILE_TYPE_MAP.put("wpd", "FF575043"); //WordPerfect (wpd)
        FILE_TYPE_MAP.put("eps", "252150532D41646F6265");
        FILE_TYPE_MAP.put("ps", "252150532D41646F6265");
        FILE_TYPE_MAP.put("pdf", "25504446"); //Adobe Acrobat (pdf)
        FILE_TYPE_MAP.put("qdf", "AC9EBD8F"); //Quicken (qdf)
        FILE_TYPE_MAP.put("pwl", "E3828596"); //Windows Password (pwl)
        FILE_TYPE_MAP.put("wav", "57415645"); //Wave (wav)
        FILE_TYPE_MAP.put("avi", "41564920");
        FILE_TYPE_MAP.put("ram", "2E7261FD"); //Real Audio (ram)
        FILE_TYPE_MAP.put("rm", "2E524D46"); //Real Media (rm)
        FILE_TYPE_MAP.put("mpg", "000001BA"); //
        FILE_TYPE_MAP.put("mov", "6D6F6F76"); //Quicktime (mov)
        FILE_TYPE_MAP.put("asf", "3026B2758E66CF11"); //Windows Media (asf)
        FILE_TYPE_MAP.put("mid", "4D546864"); //MIDI (mid)
        FILE_TYPE_MAP.put("docx", "504B0304");
        FILE_TYPE_MAP.put("xlsx", "504B0304");//excel2007以上版本文件
    }
    /**
     * @param src 要读取文件头信息的文件的byte数组
     * @return 文件头信息
     * @author wlx
     * <p>
     * 方法描述：将要读取文件头信息的文件的byte数组转换成string类型表示
     */
    private static String bytesToHexString(byte[] src) {
        StringBuilder builder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        String hv;
        for (byte aSrc : src) {
            // 以十六进制（基数 16）无符号整数形式返回一个整数参数的字符串表示形式，并转换为大写
            hv = Integer.toHexString(aSrc & 0xFF).toUpperCase();
            if (hv.length() < 2) {
                builder.append(0);
            }
            builder.append(hv);
        }
        return builder.toString();
    }
    /**
     * @Descrption: 判断文件流是那些类型的
     * @param in
     * @param suffixs
     * @return boolean
     * @throws
     */
    public static boolean isFileType(InputStream in,String ...suffixs) {
        byte[] b = new byte[4];
        try {
            if(in.read(b, 0, b.length)==-1){
                throw new ServiceException("未读取到数据");
            }
        } catch (IOException e) {
            throw new ServiceException("判断文件类型失败");
        }
        String value = bytesToHexString(b);
        for(String suffix:suffixs) {
            String fileType = FILE_TYPE_MAP.get(suffix);
            if (fileType != null && fileType.equalsIgnoreCase(value)) {
                return true;
            }
        }
        return false;
    }

    public static SysFileInfo getFileInfo(MultipartFile file) throws Exception {
        //		String md5 = fileMd5(file.getInputStream());

        SysFileInfo fileInfo = new SysFileInfo();
        // fileInfo.setId(md5);// 将文件的md5设置为文件表的id
        fileInfo.setName(file.getOriginalFilename());
        fileInfo.setContentType(file.getContentType());
        fileInfo.setIsimg(
                fileInfo.getContentType().startsWith("image/") ? Constant.YES : Constant.NO);
        fileInfo.setSize(file.getSize());
        fileInfo.setCreateTime(new Date());

        return fileInfo;
    }

    public static SysFileInfo getFileInfo(File file,SysFileInfo fileInfo) throws Exception {
        //		String md5 = fileMd5(file.getInputStream());

        // fileInfo.setId(md5);// 将文件的md5设置为文件表的id
        fileInfo.setName(file.getName());
        fileInfo.setIsimg(Constant.NO);
        fileInfo.setSize(file.length());
        fileInfo.setCreateTime(new Date());

        return fileInfo;
    }

    /**
     * 文件的md5
     *
     * @param inputStream
     * @return
     */
    public static String fileMd5(InputStream inputStream) {
        try {
            return DigestUtils.md5Hex(inputStream);
        } catch (IOException e) {
            logger.error("file md5 error", e);
        }

        return null;
    }

    /**
     * 将文件保存到本地
     *
     * @param file
     * @param path
     * @return
     */
    public static String saveFile(MultipartFile file, String path) {
        try {
            File targetFile = new File(path);
            if (targetFile.exists()) {
                return path;
            }
            boolean parentCreated = targetFile.getParentFile().mkdirs();
            if (!parentCreated) {
                logger.error("创建文件夹失败");
            }
            file.transferTo(targetFile);
            return path;
        } catch (IOException e) {
            logger.error("saveFile error", e);
        }
        return null;
    }

    /**
     * 删除本地文件
     *
     * @param pathname
     * @return
     */
    public static boolean deleteFile(String pathname) {
        File file = new File(pathname);
        if (!file.exists()) {
            return false;
        }
        boolean flag = file.delete();
        if (!flag) {
            return false;
        }
        File parentDir = file.getParentFile();
        File[] files = parentDir.listFiles();
        if (files == null || files.length == 0) {
            return parentDir.delete();
        }
        return true;
    }

    /**
     * 读取到字节数组2
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public static byte[] toByteArray2(String filePath) throws IOException {
        File f = new File(filePath);
        if (!f.exists()) {
            throw new FileNotFoundException(filePath);
        }
        FileChannel channel = null;
        FileInputStream fs = null;
        try {
            fs = new FileInputStream(f);
            channel = fs.getChannel();
            ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());
            while ((channel.read(byteBuffer)) > 0) {
                // do nothing
                // System.out.println("reading");
            }
            return byteBuffer.array();
        } catch (IOException e) {
            logger.error("读取文件到字节数组：", e);
            throw e;
        } finally {
            try {
                if (channel != null) {
                    channel.close();
                }
            } catch (IOException e) {
                logger.error("读取文件到字节数组：", e);
            }
            try {
                if (fs != null) {
                    fs.close();
                }
            } catch (IOException e) {
                logger.error("读取文件到字节数组：", e);
            }
        }
    }

}
